#include <iostream>
#include <chrono>
#include <ratio>

int main(int argc, char* argv[]) {

    /*
        std::ratio 类模板提供编译时的有理数支持, 通过模板参数指定分子分母
        分母默认为1且不能为0, 标准还对部分值进行了 typedef 声明如 nano
        就表示 std::ratio<1, 1000000000>
    */
    std::ratio<60, 1> minute;
    std::ratio<60 * 60> hour;

    /*
        类模板 std::chrono::duration 表示时间间隔
        类模板声明为 template<class Rep, class Period = std::ratio<1>> class duration
        Rep 是计数的类型, Period 表示计数周期, 表示从一个计数到下一个的秒数, 默认 1 s
        标准同样对一些特殊时间单位进行了 typedef 声明, 如 std::chrono::minutes 表示
        duration<至少29为有符号整数, std::ratio<60>>
    */

    // 定义一个整数类型的 100 秒时间间隔类型
    typedef std::chrono::duration<int, std::ratio<100>> my_duration_type;

    // duration 的构造函数还接收一个数值表示多少个时间周期, 例如表示 3 分钟
    std::chrono::duration<int, std::ratio<3 * 60>> minute1{1};  // 1个3分钟
    std::chrono::minutes minute2{3};    // 3个1分钟
    std::chrono::duration<double, std::ratio<2 * 60>> minute3{1.5}; // 1.5个2分钟
    // count 方法查看包含了多少个时间间隔
    std::cout << minute3.count() << std::endl;

    // std::duration_cast 支持单位转换, 如分钟转换为秒
    int seconds = std::chrono::duration_cast<std::chrono::seconds>(minute1).count();
    std::cout << seconds << std::endl;

    /*
        std::chrono::time_point 用来表示一个时间点, 它有一个成员函数
        time_since_epoch() 可以返回从 epoch 时间到指定时间点的时间间隔
        默认应该是以秒为单位
    */
    auto p0 = std::chrono::time_point<std::chrono::system_clock>{};
    auto p1 = std::chrono::system_clock::now(); // 获取系统当前的时间点
    auto p2 = p1 - std::chrono::hours(24);  // 获取 p1 前一天的时间点

    // 转换成 c 风格的时间类型
    time_t epoch_time = std::chrono::system_clock::to_time_t(p0);
    std::cout << "epoch: " << std::ctime(&epoch_time);
    time_t today_time = std::chrono::system_clock::to_time_t(p1);
    std::cout << "today: " << std::ctime(&today_time);

    // 输出从 epoch 距离今天有多少个小时
    std::cout << "hours since epoch: " << std::chrono::duration_cast<std::chrono::hours>(p1.time_since_epoch()).count() << '\n';
    // 距离昨天
    std::cout << "yesterday since epoch: " << std::chrono::duration_cast<std::chrono::hours>(p2.time_since_epoch()).count() << '\n';

    /*
        std::chrono::steady_clock 表示单调时钟, 此时钟的时间点无法减少，因为物理时间向前移动
        最适合用于度量时间间隔
    */

    // 返回类型比较长, 可以用 auto 推断
    std::chrono::time_point<std::chrono::steady_clock> start = std::chrono::steady_clock::now();

    for (int i = 0; i < 1000000000; i++) {
        // do_something
    }

    auto end = std::chrono::steady_clock::now();
    std::chrono::duration<double> elapsed = end - start;
    std::cout << "cost time : " << elapsed.count() << " s" << std::endl;

    /*
        std::chrono::high_resolution_clock 表示实现提供的拥有最小计次周期的时钟。
        它可以是 std::chrono::system_clock 或 std::chrono::steady_clock 的别名，或第三个独立时钟。
    */

    auto st = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 1000000000; i++) {}
    auto ed = std::chrono::high_resolution_clock::now();
    elapsed = ed - st;
    std::cout << "cost time : " << elapsed.count() << " s" << std::endl;
    return 0;
}